home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
intrvews
/
acme.lha
/
acme
/
src
/
acme_server
/
sparcstation.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-29
|
10KB
|
398 lines
// Copyright (c) 1991 The Regents of the University of California.
// All Rights Reserved.
// The University of California makes no representations about
// the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
// SPARCSTATION-DEPENDENT
// (although the same structure can probably be used for other platforms)
#define SHOW_AUDIO
#include <sys/ioctl.h>
#include <sys/file.h>
#include <signal.h>
#include <fcntl.h>
#include <stropts.h>
#include <errno.h>
#include <stdio.h>
extern "C" {
#include <sys/mman.h>
}
#include "sparcstation.h"
#include "pdev.h"
#include "io.h"
#include "process.h"
#include "synch.h"
#include "scheduler.h"
#include "signals.h"
#include "ldev.h"
#include "fifo.h"
#include "defs.h"
#include "debug.h"
LIST pdevs;
// AUDIO OUTPUT
// Audio output uses the SunOS 4.1 audio device driver
// and the Sparcstation 1+ built-in speaker
// Buffer for accumulating audio output from all audio out ldevs.
// Samples are linear, 12 bit, word aligned
int sum_buf[AUDIO_OUT_BLOCK_SIZE];
// output buffer for writes to kernel audio device.
// Samples are mulaw, 8 bit
unsigned char out_buf[AUDIO_OUT_BLOCK_SIZE];
BOOLEAN SPARC_AUDIO_OUT::play(LDEV* ldev) {
MSG_BUF *b = &(ldev->fifo->rbuf);
int *p, *q;
int numleft;
int j;
if (ldev->fifo->get_rbuf(AUDIO_OUT_BLOCK_SIZE << 2, FALSE)) {
q = sum_buf;
ldev->update_pdev_time(period);
numleft = AUDIO_OUT_BLOCK_SIZE << 2;
while (numleft) {
p = (int*) b->data;
numleft -= b->nbytes;
if (ldev->is_mapped) {
for (j=0; j<((b->nbytes) >> 2); j++) {
*q++ += *p++;
}
}
ldev->fifo->read_done();
if (numleft) ldev->fifo->get_rbuf(numleft, FALSE);
}
return TRUE;
}
return FALSE;
}
BOOLEAN SPARC_AUDIO_OUT::skip(LDEV *ldev) {
MSG_BUF *b = &(ldev->fifo->rbuf);
int numleft;
if (ldev->fifo->get_rbuf(AUDIO_OUT_BLOCK_SIZE << 2, FALSE)) {
ldev->update_pdev_time(period);
numleft = AUDIO_OUT_BLOCK_SIZE << 2;
while (numleft) {
numleft -= b->nbytes;
ldev->fifo->read_done();
if (numleft) ldev->fifo->get_rbuf(numleft, FALSE);
}
return TRUE;
}
return FALSE;
}
// add together a block of data from all LDevs mapped to the speaker.
// convert it to ulaw, then write it out.
// Then write zero-length buffer for asynchronous interrupt.
void SPARC_AUDIO_OUT::output_block(){
bzero(sum_buf, sizeof(sum_buf)); // prepare sum_buf for accumulation
call_lts();
// Now we've accumulated all the output.
// Convert it to mulaw and write it out
unsigned char *r = out_buf;
int *p = sum_buf;
for (int i=0; i<AUDIO_OUT_BLOCK_SIZE; i++) {
*r++ = linear_to_mulaw[(*p++ + 2048) & 4095];
}
#ifdef SHOW_AUDIO
*(sparc_video_out->fb_base+data_fd*2) = out_buf[0];
*(sparc_video_out->fb_base+data_fd*2+1) = 0;
#endif
write(data_fd, out_buf, AUDIO_OUT_BLOCK_SIZE);
write(data_fd, out_buf, 0); // zero length buf to get sigio
update_lts_values();
}
// The audio out process does the following:
// Initially write two buffers, then sleep, waiting for SIGIO.
// When SIGIO handler finds at least one buffer is done, awaken this process.
// When awakened, write enough blocks so two are pending, then sleep again.
void sparc_audio_output(SPARC_AUDIO_OUT *pdev) {
mask_ints();
pdev->output_block();
pdev->output_block();
for (;;) {
WHO->deadline = TIMER::current_time + pdev->period;
pdev->cot.sleep_on();
while (pdev->left_to_write) {
pdev->output_block();
pdev->left_to_write--;
}
}
}
SPARC_AUDIO_OUT::SPARC_AUDIO_OUT(
PHYSICAL_SCOPE s,
MEDIUM m,
DIRECTION d,
TIME p,
float xbar
) : (s, m, d, p, xbar) {
if ((data_fd = open(AUDIO_DEVICE, O_WRONLY | O_NDELAY)) < 0)
PANICERR("audio_out: couldn't open audio output device");
if (ioctl(data_fd, I_SETSIG, (char*)(S_INPUT|S_OUTPUT|S_MSG)) != 0)
PANICERR("audio_out: error in I_SETSIG ioctl on device");
if ((ctl_fd = open(AUDIO_CTL_DEVICE, O_RDWR | O_NDELAY)) < 0)
PANICERR("audio_out: couldn't open audio control device");
if (ioctl(ctl_fd, I_SETSIG, (char*)S_MSG) != 0)
PANICERR("audio_out: error I_SETSIG on pseudo device");
types << (void*) AUDIO_MULAW_8_8000
<< (void*) AUDIO_MULAW_8_4000;
left_to_write = 0;
}
void init_audio_out() {
SPARC_AUDIO_OUT* p = new SPARC_AUDIO_OUT(
WORKSTATION,
AUDIO,
OUT,
(TIME) (double) AUDIO_OUT_BLOCK_SIZE / (double) AUDIO_OUT_SAMPLING_RATE,
XBAR
);
sparc_audio_out = p;
pdevs << (void*) p;
SCHEDULER::run(
new PROCESS(
(PROCEDURE)sparc_audio_output,
ARGS() << p,
TIMER::current_time,
"audio out"
)
);
}
// AUDIO INPUT
// These variables and functions are for audio input using the SunOS 4.1
// audio device driver and the Sparcstation 1+ built in microphone input.
// buffer filled with audio samples by audio device driver.
// samples are mu law, 8 bit
unsigned char in_buf[AUDIO_IN_BLOCK_SIZE];
// zero analog value is stored here in mu law encoding
unsigned char mulaw_zero;
BOOLEAN SPARC_AUDIO_IN::skip(LDEV *ldev) {
MSG_BUF *b = &(ldev->fifo->wbuf);
int numleft;
unsigned char *p;
int j;
if (ldev->fifo->get_wbuf(AUDIO_IN_BLOCK_SIZE, FALSE)) {
ldev->update_pdev_time(period);
numleft = AUDIO_IN_BLOCK_SIZE;
while (numleft) {
numleft -= b->nbytes;
p = (unsigned char *) b->data;
for (j=0; j<b->nbytes; j++) {
*p++ = mulaw_zero;
}
ldev->fifo->write_done();
if (numleft) ldev->fifo->get_wbuf(numleft, FALSE);
}
return TRUE;
}
return FALSE;
}
BOOLEAN SPARC_AUDIO_IN::play(LDEV *ldev) {
MSG_BUF *b = &(ldev->fifo->wbuf);
int numleft;
unsigned char *p, *q;
int j;
if (ldev->fifo->get_wbuf(AUDIO_IN_BLOCK_SIZE, FALSE)) {
q = in_buf;
ldev->update_pdev_time(period);
numleft = AUDIO_IN_BLOCK_SIZE;
while (numleft) {
if (ldev->is_mapped) {
bcopy(q, b->data, b->nbytes);
} else {
p = (unsigned char *) b->data;
for (j=0; j<b->nbytes; j++) {
*p++ = mulaw_zero;
}
}
numleft -= b->nbytes;
q += b->nbytes;
ldev->fifo->write_done();
if (numleft) ldev->fifo->get_wbuf(numleft, FALSE);
}
return TRUE;
}
return FALSE;
}
// the audio input process executes this routine
void sparc_audio_input(SPARC_AUDIO_IN* pdev) {
for (;;) {
int i = pdev->io->read((char*)in_buf, AUDIO_IN_BLOCK_SIZE, FALSE);
if (i < 0) PANIC("audio read failed");
mask_ints();
pdev->call_lts();
pdev->update_lts_values();
WHO->change_deadline(TIMER::current_time + pdev->period);
unmask_ints();
}
}
SPARC_AUDIO_IN::SPARC_AUDIO_IN (
PHYSICAL_SCOPE s,
MEDIUM m,
DIRECTION d,
TIME p,
float xbar
) : (s, m, d, p, xbar) {
if ((fd = open(AUDIO_DEVICE, O_RDONLY | O_NDELAY)) < 0)
PANIC("audio_in: couldn't open audio input device");
io = new IO(fd);
mulaw_zero = linear_to_mulaw[2048];
types << (char*) AUDIO_MULAW_8_8000;
}
void init_audio_in() {
SPARC_AUDIO_IN* p = new SPARC_AUDIO_IN(
WORKSTATION,
AUDIO,
IN,
(TIME) (double) AUDIO_IN_BLOCK_SIZE / (double) AUDIO_IN_SAMPLING_RATE,
XBAR
);
pdevs << p;
SCHEDULER::run(
new PROCESS(
(PROCEDURE)sparc_audio_input,
ARGS() << p,
TIMER::current_time,
"audio in"
)
);
}
// VIDEO OUTPUT
// Uncompressed monochrome video output
// to the Sparcstation 1 monochrome framebuffer, under SunOS 4.1
BOOLEAN SPARC_VIDEO_OUT::play(LDEV *lldev) {
VIDEO_OUT_LDEV*ldev = (VIDEO_OUT_LDEV*) lldev;
MSG_BUF *b = &(ldev->fifo->rbuf);
char* fbp = ldev->base;
char* fbbase = fbp;
int nleft = ldev->bytes_line;
int numleft;
if (ldev->fifo->get_rbuf(ldev->bytes_frame, FALSE)) {
ldev->update_pdev_time(period);
numleft = ldev->bytes_frame;
while (numleft) {
char* p = b->data;
int k = b->nbytes;
if (ldev->is_mapped) {
while (k) {
int ncopy = min(nleft, k);
bcopy(p, fbp, ncopy);
k -= ncopy;
nleft -= ncopy;
p += ncopy;
fbp += ncopy;
if (nleft == 0) {
nleft = ldev->bytes_line;
fbbase += FB_BYTES_LINE;
fbp = fbbase;
}
}
}
numleft -= b->nbytes;
ldev->fifo->read_done();
if (numleft) ldev->fifo->get_rbuf(numleft, FALSE);
}
return TRUE;
}
return FALSE;
}
BOOLEAN SPARC_VIDEO_OUT::skip(LDEV *lldev) {
VIDEO_OUT_LDEV*ldev = (VIDEO_OUT_LDEV*) lldev;
MSG_BUF *b=&(ldev->fifo->rbuf);
int numleft;
if (ldev->fifo->get_rbuf(ldev->bytes_frame, FALSE)) {
ldev->update_pdev_time(period);
numleft = ldev->bytes_frame;
while (numleft) {
numleft -= b->nbytes;
ldev->fifo->read_done();
if (numleft) ldev->fifo->get_rbuf(numleft, FALSE);
}
return TRUE;
}
return FALSE;
}
// the video output process executes this
void sparc_video_output(SPARC_VIDEO_OUT *pdev) {
mask_ints();
for (;;) {
pdev->call_lts();
pdev->update_lts_values();
WHO->deadline += pdev->period;
pdev->cot.sleep_on();
}
}
SPARC_VIDEO_OUT::SPARC_VIDEO_OUT(
PHYSICAL_SCOPE s,
MEDIUM m,
DIRECTION d,
TIME p,
float xbar
) : (s, m, d, p, xbar) {
int d = open("/dev/fb", O_RDWR, 0);
fb_base = mmap(0, 0x20000, PROT_WRITE, MAP_SHARED, d, 0);
types << (char*) VIDEO_UNC_MONO;
}
void init_video_out() {
SPARC_VIDEO_OUT* p = new SPARC_VIDEO_OUT(
WORKSTATION,
VIDEO,
OUT,
1.0/VIDEO_FPS,
XBAR
);
sparc_video_out = p;
pdevs << p;
SCHEDULER::run(
p->process = new PROCESS(
(PROCEDURE)sparc_video_output,
ARGS() << p,
TIMER::current_time,
"video out"
)
);
}
void init_pdevs() {
init_audio_out();
init_audio_in();
init_video_out();
}